
package net.lab0.fractal.classes;


import java.awt.Dimension;
import java.awt.Point;
import java.awt.geom.Point2D;


public class RenderingCoordinates
extends ViewCoordinates
{
    private int xResolution;
    private int yResolution;
    
    public RenderingCoordinates(RenderingCoordinates renderingCoordinates)
    {
        super(renderingCoordinates);
        this.xResolution = renderingCoordinates.xResolution;
        this.yResolution = renderingCoordinates.yResolution;
    }
    
    public RenderingCoordinates(ViewCoordinates coordinates, int xResolution, int yResolution)
    {
        super(coordinates);
        
        if (xResolution > 0 && yResolution > 0)
        {
            this.xResolution = xResolution;
            this.yResolution = yResolution;
        }
        else
        {
            throw new IllegalArgumentException("Resolution must be at least 1x1");
        }
    }
    
    public RenderingCoordinates(Double xCenter, Double yCenter, Double width, Double height, int xResolution, int yResolution)
    {
        super(xCenter, yCenter, width, height);
        
        if (xResolution > 0 && yResolution > 0)
        {
            this.xResolution = xResolution;
            this.yResolution = yResolution;
        }
        else
        {
            throw new IllegalArgumentException("Resolution must be at least 1x1");
        }
    }
    
    public Double getScaledWidth()
    {
        if (getResolutionScale() > getViewScale())
        {
            return getWidth() / getViewScale() * getResolutionScale();
        }
        else
        {
            return getWidth();
        }
    }
    
    public Double getScaledHeight()
    {
        if (getResolutionScale() > getViewScale())
        {
            return getHeight();
        }
        else
        {
            return getHeight() * getViewScale() / getResolutionScale();
        }
    }
    
    public int getxResolution()
    {
        return xResolution;
    }
    
    public int getyResolution()
    {
        return yResolution;
    }
    
    public void setxResolution(int xResolution)
    {
        if (xResolution > 0)
        {
            this.xResolution = xResolution;
        }
    }
    
    public void setyResolution(int yResolution)
    {
        if (yResolution > 0)
        {
            this.yResolution = yResolution;
        }
    }
    
    public void setResolution(Dimension size)
    {
        if (size.width > 0)
        {
            xResolution = size.width;
        }
        if (size.height > 0)
        {
            yResolution = size.height;
        }
    }
    
    public Double getResolutionScale()
    {
        return (double) xResolution / (double) yResolution;
    }
    
    public Point toScreenCoordinates(Point2D.Double p)
    {
        int X = (int) (getxResolution() * (p.x - getxCenter() + getScaledWidth() / 2) / getScaledWidth());
        int Y = (int) (getyResolution() * (getyCenter() + getScaledHeight() / 2 - p.y) / getScaledHeight());
        return new Point(X, Y);
    }
    
    public Point toScreenCoordinates(double x, double y)
    {
        return toScreenCoordinates(new Point2D.Double(x, y));
    }
    
    public Point2D.Double toRenderingCoordinates(Point p)
    {
        double x = p.x * getScaledWidth() / getxResolution() + getxCenter() - getScaledWidth() / 2;
        double y = -(p.y * getScaledHeight() / getyResolution() - getyCenter() - getScaledHeight() / 2);
        return new Point2D.Double(x, y);
        
    }
    
    public double getViewScale()
    {
        return getWidth() / getHeight();
    }
    
    public Point2D.Double getScaledTopLeftCorner()
    {
        return new Point2D.Double(getxCenter() - getScaledWidth() / 2, getyCenter() + getScaledHeight() / 2);
    }
    
    public Point2D.Double getScaledTopRightCorner()
    {
        return new Point2D.Double(getxCenter() + getScaledWidth() / 2, getyCenter() + getScaledHeight() / 2);
    }
    
    public Point2D.Double getScaledBottomLeftCorner()
    {
        return new Point2D.Double(getxCenter() - getScaledWidth() / 2, getyCenter() - getScaledHeight() / 2);
    }
    
    public Point2D.Double getScaledBottomRightCorner()
    {
        return new Point2D.Double(getxCenter() + getScaledWidth() / 2, getyCenter() - getScaledHeight() / 2);
    }
    
    @Override
    public int hashCode()
    {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result + xResolution;
        result = prime * result + yResolution;
        return result;
    }
    
    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
            return true;
        if (!super.equals(obj))
            return false;
        if (getClass() != obj.getClass())
            return false;
        RenderingCoordinates other = (RenderingCoordinates) obj;
        if (xResolution != other.xResolution)
            return false;
        if (yResolution != other.yResolution)
            return false;
        return true;
    }
    
    @Override
    protected Object clone()
    throws CloneNotSupportedException
    {
        return new RenderingCoordinates(this);
    }
}
